package com.zackeus.mvvm.api.response;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.google.gson.Gson;
import com.zackeus.mvvm.api.ExceptionHandle;
import com.zackeus.common.utils.ObjectUtils;

import java.lang.reflect.ParameterizedType;
import java.net.HttpURLConnection;
import java.util.Objects;

import okhttp3.ResponseBody;
import retrofit2.HttpException;

/**
 * @name: CommonResponseObserver
 * @author: zz
 * @date: 2022/9/1
 */
public abstract class CommonResponseObserver<T extends Response> implements ResponseObserver<T> {

    /* 自定义异常 */
    private static final ResponseThrowable ERROR = new ResponseThrowable(
            HttpURLConnection.HTTP_INTERNAL_ERROR,
            ResponseStatus.HTTP_SERVER_ERROR,
            new Exception("API Custom exception.")
    );

    @Override
    public void onBeforeStart() {

    }

    @Override
    public void onStart() {

    }

    @Override
    public final void onNext(T t) {
        if (t.isOk()) {
            onSuccess(t);
        } else {
            onError(t, ERROR);
        }
    }

    @Override
    public final void onError(Throwable throwable) {
        if (throwable instanceof HttpException) {
            retrofit2.Response<?> response = ((HttpException) throwable).response();
            if (ObjectUtils.isNotNull(response)) {
                try {
                    /* 解析异常body 有可能是API自定义异常 */
                    ResponseBody body = response.errorBody();

                    /* 反射解析实体 */
                    ParameterizedType type = (ParameterizedType) getClass().getGenericSuperclass();
                    T t = new Gson().fromJson(Objects.requireNonNull(body).string(),
                            Objects.requireNonNull(type).getActualTypeArguments()[0]);

                    onError(t, ERROR);
                    return;
                } catch (Exception ignored) {}
            }
        }

        onError(null, ExceptionHandle.handleException(throwable));
    }

    @Override
    public final void onComplete() {

    }

    @Override
    public final void onFinally() {
        onEnd();
    }

    public abstract void onSuccess(T t);
    public abstract void onError(@Nullable T t, @NonNull ResponseThrowable e);

    public void onEnd() {

    }
}
